package com.woniuxy.shiro;

import com.woniuxy.dao.ManagerDao;
import com.woniuxy.entity.Manager;
import com.woniuxy.entity.MyJsonWebToken;
import com.woniuxy.util.JWTUtil;
import com.woniuxy.util.RedisUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component("authorizer")
public class MyRealm extends AuthorizingRealm {

    @Resource
    ManagerDao managerDao;
    @Resource
    RedisUtils redisUtils;

    @Override
    public void setName(String name){
        super.setName("myRealm");
    }


    // 这个需要注意下, 多域模式中, 每个域里面 请自己配置自己的token来源
    // 这里的token是来自 自定义的JWTToken
    // 必须重写此方法，不然 传的jwt, shiro却使用的是UsernamePasswordToken进行解析,
    // 会报一个错, 你token格式不对(JWT的值是3部分, UsernamePasswordToken只有1节....)
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof MyJsonWebToken;
    }

    /**
     * 授权信息
     * 在前后端不分离的情况下, 在html页面使用<shiro>|后端使用shiro的@checkRole,@checkPermission相关注解才能触发
     * 前后端分离的模式, 就直接用注解验证权限即可, 根据需求来
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("MyRealm.doGetAuthorizationInfo, 授权方法进入!!!");
        //这里得去获取到这个token 不用token过滤器 直接从redis里面拿数据
        String userName = JWTUtil.getUserName(principals.toString());
        //去数据库查询用户信息，含角色（也含权限）
        Manager user = this.managerDao.queryByUsername(userName);
        //授权信息集合
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //1.如果需求是角色可以配置多个，则如下获取所有角色 并放入授权信息集合（模拟多角色查询，虽然目前是单的）
        String roles = String.valueOf(user.getRoleId());
        System.out.println("!!!!!!!!!!!!!!!!"+roles);
        if(!"".equals(roles)&&roles!=null){
            String[] roles1 = roles.split(",");
            for (String role : roles1) {
                simpleAuthorizationInfo.addRole(role);
            }
        }
        //2.目前是单个角色则直接这样用吧.....
       simpleAuthorizationInfo.addRole(user.getRoleId()+"");
        //3.通过角色, 去查询中间表 找到所有的权限  获取tyep字段,a接口权限link细节信息(同第1步)

        return simpleAuthorizationInfo;
    }

    /**
     * 身份认证方法
     * 需要在用户登录系统时触发
     * 该方法将是我们主要的方法, 流程是登录后, 携带token 与权限信息 发送到 vue中 存储浏览器
     * 在页面渲染时,直接传入菜单和 页面按钮显示权限
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("MyRealm.doGetAuthenticationInfo, 用户认证方法进入!");
        String myJWT=(String) token.getCredentials();
        String username= JWTUtil.getUserName(myJWT);
        if(username == null){
            throw new AuthenticationException("token无效");
        }
        //通过用户名，查出当前用户密码
        Manager user = this.managerDao.queryByUsername(username);

        if(user==null){
            throw new AuthenticationException("User 不存在");
        }
        //通过存入的myJWT与传入的账号密码进行验证，账号密码是否争取（类比之前手动比较密码）
        if (JWTUtil.verify(myJWT,username,user.getPassword())){
            return new SimpleAuthenticationInfo(myJWT,myJWT,this.getName());
        }else{
            throw new AuthenticationException("用户名或者密码错误");
        }
    }
}
